package com.example.demo.service;

import com.example.demo.dto.UploadDownloadHistoryDTO;
import com.example.demo.mapper.*;
import com.example.demo.model.*;
import com.example.demo.utils.Page;
import com.example.demo.utils.RedisUtils;
import com.example.demo.utils.EmailService;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.auth.InvalidCredentialsException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class UserService {
    private final UserMapper userMapper;
    private final PasswordEncoder passwordEncoder;
    private final InviteCodeMapper inviteCodeMapper;
    private final UserCreditMapper userCreditMapper;
    private final NoticeMapper noticeMapper;
    private final UploadDownloadHistoryMapper uploadDownloadHistoryMapper;


    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private EmailService emailService;

    public UserCredit getUserCredit(Long userId) {
        return userCreditMapper.findByUserId(userId);
    }
    @Autowired
    public UserService(UserMapper userMapper,
                       PasswordEncoder passwordEncoder,
                       InviteCodeMapper inviteCodeMapper,
                       UserCreditMapper userCreditMapper, NoticeMapper noticeMapper, UploadDownloadHistoryMapper uploadDownloadHistoryMapper) {
        this.userMapper = userMapper;
        this.passwordEncoder = passwordEncoder;
        this.inviteCodeMapper = inviteCodeMapper;
        this.userCreditMapper = userCreditMapper;
        this.noticeMapper = noticeMapper;
        this.uploadDownloadHistoryMapper = uploadDownloadHistoryMapper;
    }

    /* 原有方法保持不变 */
    @Async
    public void sendVerificationCode(String email) {
        if (!StringUtils.hasText(email)) {
            throw new IllegalArgumentException("邮箱不能为空");
        }

        String verificationCode = generateRandomCode();
        redisUtils.set("verify:" + email, verificationCode, 30, TimeUnit.MINUTES);
        System.out.println("send code in redis\n"+redisUtils.get("verify:" + email));
        emailService.sendEmail(email, "注册验证码", "您的验证码是：" + verificationCode);
    }

    public boolean verifyCode(String email, String code) {
        if (!StringUtils.hasText(email) || !StringUtils.hasText(code)) {
            return false;
        }
        System.out.println("code from redis\n"+redisUtils.get("verify:" + email));

        String storedCode = redisUtils.get("verify:" + email);

        if (storedCode != null && storedCode.equals(code)) {
            redisUtils.delete("verify:" + email);
            return true;
        }
        return false;
    }

    private String generateRandomCode() {
        Random random = new Random();
        return String.format("%06d", random.nextInt(1000000));
    }

    public User findByEmail(String email) {
        return userMapper.findByEmail(email);
    }

    public User findById(Long id) {
        return userMapper.selectUserById(id);
    }

    public User findByUsername(String username) {
        User user = userMapper.findByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("用户不存在");
        }
        return user;
    }

    @Transactional
    public void forgetPassword(String email, String code, String newPassword) {
        User user = userMapper.findByEmail(email);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }

        // 验证验证码
        if (!verifyCode(user.getEmail(), code)) {
            throw new RuntimeException("验证码错误或已过期");
        }

        user.setPassword(passwordEncoder.encode(newPassword));
        userMapper.updatePassword(user.getId(),user.getPassword());
    }

    /* 修改后的注册方法（新增邀请码验证） */
    @Transactional
    public void registerUser(User user, String code, String inviteCode) {
        // 验证用户名和邮箱
        if (userMapper.findByUsername(user.getUsername()) != null) {
            throw new RuntimeException("用户名已存在");
        }
        if (userMapper.findByEmail(user.getEmail()) != null) {
            throw new RuntimeException("邮箱已被注册");
        }

        // 验证验证码
        if (!verifyCode(user.getEmail(), code)) {
            throw new RuntimeException("验证码错误或已过期");
        }

        // 验证邀请码
        InviteCode invite = inviteCodeMapper.findByCode(inviteCode);
        if (invite == null || invite.isUsed() || invite.isExpired()) {
            throw new RuntimeException("邀请码无效或已使用");
        }

        // 保存用户
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        user.setRole("USER");

        userMapper.insertUser(user);
        // 创建用户积分
        UserCredit credit = new UserCredit();
        credit.setUserId(user.getId());
        credit.setBalance(0);
        credit.setTotalBalance(0);
        userCreditMapper.insertUserCredit(credit);

        // 更新邀请码状态
        invite.setUsed(true);
        invite.setUsedBy(user.getId());
        invite.setUsedAt(LocalDateTime.now());
        inviteCodeMapper.update(invite);
    }

    /* 管理员注册方法保持不变 */
    @Transactional
    public void registerAdmin(User adminUser, String verificationCode) {
        if (userMapper.findByUsername(adminUser.getUsername()) != null) {
            throw new RuntimeException("用户名已存在");
        }
//        if (!verifyCode(adminUser.getEmail(), verificationCode)) {
//            throw new RuntimeException("验证码错误或已过期");
//        }

        adminUser.setPassword(passwordEncoder.encode(adminUser.getPassword()));
        adminUser.setRole(User.ROLE_ADMIN);
        userMapper.insertUser(adminUser);
    }

    public Boolean getBanStatusByEmail(String email){
        return userMapper.getBanStatusByEmail(email);
    }

    public Long getCurrentUserId(Authentication authentication) {
        if (authentication == null || !authentication.isAuthenticated()) {
            return null;
        }

        Object principal = authentication.getPrincipal();

        // 情况1：principal是UserDetails实现类
        if (principal instanceof UserDetails) {
            String username = ((UserDetails) principal).getUsername();
            User user = findByUsername(username);
            return user != null ? user.getId() : null;
        }

        // 情况2：principal是String（用户名）
        if (principal instanceof String) {
            User user = findByUsername((String) principal);
            return user != null ? user.getId() : null;
        }

        return null;
    }

    @Transactional(rollbackFor = Exception.class)
    public void changePassword(User user, String code, String oldPassword, String newPassword) {
        // 验证验证码
        if (!verifyCode(user.getEmail(), code)) {
            throw new RuntimeException("验证码错误或已过期");
        }

        // 验证旧密码
        if (!passwordEncoder.matches(oldPassword, user.getPassword())) {
            try {
                throw new InvalidCredentialsException("旧密码错误");
            } catch (InvalidCredentialsException e) {
                throw new RuntimeException(e);
            }
        }

        // 更新密码
        String encodedPassword = passwordEncoder.encode(newPassword);
        userMapper.updatePassword(user.getId(), encodedPassword);

    }

    @Transactional
    public void completePasswordReset(String token, String newPassword) {
        // 验证token
        String userIdStr = redisUtils.get("password_reset:" + token);
        if (userIdStr == null) {
            throw new RuntimeException("密码重置链接无效或已过期");
        }

        // 获取用户
        Long userId = Long.parseLong(userIdStr);
        User user = userMapper.selectUserById(userId);
        if (user == null) {
            throw new RuntimeException("用户不存在");
        }

        // 更新密码
        String encodedPassword = passwordEncoder.encode(newPassword);
        userMapper.updatePassword(userId, encodedPassword);

        // 删除token
        redisUtils.delete("password_reset:" + token);
    }

    public Map<String, Object> getUserBalance(Long userId) {
        Map<String, Object> response = new HashMap<>();

        // 查询积分
        UserCredit credit = userCreditMapper.findByUserId(userId);
        if (credit == null) {
            response.put("success", false);
            response.put("message", "积分记录不存在");
            return response;
        }

        // 返回结果
        response.put("success", true);
        response.put("userId", userId);
        response.put("balance", credit.getBalance());
        return response;

    }

    @Transactional
    public void updateUserName(Long userId, String userName){
        userMapper.updateUserName(userId, userName);
    }

    @Transactional
    public String findEmailByUsername(String username) {
        return userMapper.findEmailByUsername(username);
    }

    public List<Notice> getAllNotices() {
        return noticeMapper.findAll();
    }

    public List<UploadDownloadHistoryDTO> getUploadHistory(Long userId) {
        log.info("查询用户 {} 的上传历史", userId);
        try {
            List<UploadDownloadHistoryDTO> result = uploadDownloadHistoryMapper.findByUserIdAndActionType(userId, "UPLOAD");
            log.info("找到 {} 条上传记录", result.size());
            return result;
        } catch (Exception e) {
            log.error("查询用户 {} 的上传历史失败", userId, e);
            throw e;
        }
    }

    public List<UploadDownloadHistoryDTO> getDownloadHistory(Long userId) {
        log.info("查询用户 {} 的下载历史", userId);
        try {
            List<UploadDownloadHistoryDTO> result = uploadDownloadHistoryMapper.findByUserIdAndActionType(userId, "DOWNLOAD");
            log.info("找到 {} 条下载记录", result.size());
            return result;
        } catch (Exception e) {
            log.error("查询用户 {} 的下载历史失败", userId, e);
            throw e;
        }
    }
}